/*
 * Alloy Analyzer
 * Copyright (c) 2002 Massachusetts Institute of Technology
 *
 * The Alloy Analyzer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The Alloy Analyzer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Alloy Analyzer; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package alloy.ast;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * An AST node.
 * <p>
 * The AST is a true tree: no subtrees are ever shared.  Leaves representing the same entity
 * (e.g. the same relation or the same quantified variable or the same integer literal)
 * are related by having {@link LeafId}s that are {@link LeafId#equal equal} (though not <code>==</code>).
 * <p>
 * <em>Note</em>: the {@link #equals} and {@link #hashCode} methods of {@link Node}s must <b>not</b> be overridden.
 * Some code builds {@link Map}s from {@link Node} to per-node information, which
 * need distinct {@link Node}s to be differentiated by {@link Map}.  Use {@link #isSameAs} to test for
 * structural equality.
 */
public interface Node extends Cloneable, Comparable {

    /**
     * gets the source location of this
     * @return the {@link Location}
     */
    Location getLocation();

    /**
     * sets the source location of this node
     * @param location_ the new {@link Location} of this
     */
    void setLocation(Location location_);

    /**
     * Returns the {@link List} of {@link Location}s of nested function invocations
     * that led to placing this node's subtree into the AST.
     * These locations will be highlighted if the user clicks
     * on this node in the GUI tree representation of the AST.
     * @see alloy.gui.ASTTree#treeSelectionListener
     * @see alloy.gui.LocDisplayer
     */
    public List /* of Location */ getInvocationLocations();

    /**
     * Adds an invocation location, to be highlighted when the user
     * clicks this node in the GUI tree representation of the AST.
     * The location indicates that this subtree of the AST appeared
     * as a result of function invocation at some place in the
     * undesugared AST.  Helps the user trace through the chain
     * of function invocations that led to this node's subtree
     * of the desugared AST.
     * Only done by {@link alloy.transform.InvocationInlineVisitor}
     * when inlining invocations.
     * @see alloy.gui.ASTTree#treeSelectionListener
     * @see alloy.gui.LocDisplayer
     */
    public void addInvocationLocation(Location invocationLocation_);

    /**
     * gets an iteration of the children of the node
     * @return the Iterator
     */
    Iterator getChildren();

    /**
     * @return the parent of this, or <code>null</code>
     * if node has no parent
     */
    Node getParent();

    /**
     * gets the number of children of this
     * @return the number of children
     */
    int numChildren();

    /**
     * @param node_ a Node
     * @return true if node_ is a child of this
     */
    boolean hasChild(Node node_);

    /**
     * get the child at the specified index
     * @param index_ index of the desired child
     * @return node at desired index
     */
    Node childAt(int index_);

    /**
     * return the index of the child
     * @param child_ the child whose index is desired
     * @return the child's index; -1 if <code>child_</code> is not a child
     */
    int indexOf(Node child_);

    /** 
     * mutate this by changing a child
     * @param index_ index of the child to be changed
     * @param node_ the new child
     */
    void setChild(int index_, Node node_);

    /**
     * mutate this by changing its parent
     * @param parent_ new parent of this
     */
    void setParent(Node parent_);

    /**
     * performs a deep copy of the node
     * @return a copy of the node, with the entire subtree also
     */
    Object copy();

    /** @return true if this is a leaf; note: not the same as testing
        whether (<code>this instanceof {@link Leaf}</code>), because some {@link Node}s
        that implement {@link Leaf} actually have children (e.g. {@link SigExpr} and
        {@link FieldExpr}). */
    boolean isLeaf();

    /**
     * get a textual representation of the node
     */
    String nodeString();

    /**
       get a textual representation of the node after replacements,
       plus possibly some extra information (for example
       the type of an expression)
    */
    String fullString();

    /**
       get a textual representation of the node after replacements,
       plus possibly some extra information (for example
       the type of an expression); use short names instead of qualified names.
    */
    String fullStringShortNames();

    /**
       annotate a node with an informative description.
       @return this node
    */
    Node annotate(String annotation_);

    /**
     * annotate a node with an informative description and location
     * using the information from the node it is replacing
     * @return this node
     */
    Node annotateReplacing(String annotation_, Node other_);

    /**
       annotate a node with an informative description describing the transformation that led to this node
       @return this node
    */
    Node annotateTransform(String transformAnnotation_);

    /**
       annotate a node with an informative description describing the transformation that led to this node
       using information from the node it is replacing
       @return this node
    */
    Node annotateTransformReplacing(String transformAnnotation_, Node other_);

    /**
       @return the annotation of a node if it exists, the empty
       String otherwise
    */
    String getAnnotation();

    /**
       @return the transform annotation of a node if it exists, the empty
       String otherwise
    */
    String getTransformAnnotation();

    /**
     * apply a visitor to this
     * @param visitor_ the {@link ASTVisitor}
     */
    void applyVisitor(ASTVisitor visitor_);

    /**
     * apply a return visitor to this
     * @param visitor_ the {@link ASTReturnVisitor}
     * @return the Object returned by the visitor
     */
    Object applyReturnVisitor(ASTReturnVisitor visitor_);

    /**
     * Test for structural equality, i.e. whether the {@link Node} passed as argument
     * is an exact copy of <code>this</code> {@link Node}.  {@link Node#equals} must
     * not be overridden to allow us to use {@link Map}s from each separate {@link Node},
     * so we define {@link #isSameAs} as a separate method with  {@link #equals}-like semantics.
     * It is always safe for {@link #isSameAs} to return <code>false</code>; but returning
     * <code>true</code> can enable some optimizations.
     */
    boolean isSameAs(Node node_);

    /** @return a pretty-printed {@link String} representing this node's subtree */
    public String pp();
}
